package com.mjk.common.core.jdbc.service.plus.provider.abstractor;

import com.mjk.common.base.model.BaseEntity;
import com.mjk.common.core.jdbc.annotation.ArcSharding;
import com.mjk.common.core.jdbc.ibatis.typehandler.handler.*;
import com.mjk.common.core.jdbc.service.plus.constns.BeeTypeEntity;
import com.mjk.common.core.jdbc.service.plus.provider.BeeDataSourceType;
import com.mjk.common.core.jdbc.service.plus.provider.interfaces.IBeeProvider;
import com.mjk.common.core.jdbc.service.plus.provider.interfaces.IBeeTypeMapping;
import com.mjk.common.core.jdbc.util.TableUtils;
import com.mjk.common.core.jdbc.util.provider.InsertSqlProvider;
import com.mjk.common.core.jdbc.util.provider.SqlProvider;
import com.mjk.common.tools.logger.BizLogger;
import com.mjk.common.tools.springextend.BeeSpringBean;
import com.mjk.common.util.ClassUtil;
import com.mjk.common.util.StrUtils;
import com.mjk.common.util.TimeUtils;
import org.apache.ibatis.type.JdbcType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.ObjectUtils;

import java.sql.Blob;
import java.sql.Clob;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;


public abstract class AbstractOracleProvider implements IBeeProvider, IBeeTypeMapping {
    private Set<BeeTypeEntity> allMapping = new HashSet<>(Arrays.asList(
            new BeeTypeEntity(JdbcType.ARRAY, "ARRAY", Long.class.getName(), "20", 0, new LongHandler()),
            new BeeTypeEntity(JdbcType.BIT, "NUMBER", Boolean.class.getName(), "4", 0, new BooleanHandler()),
            new BeeTypeEntity(JdbcType.TINYINT, "NUMBER", Byte.class.getName(), "4", 1, new ByteHandler()),
            new BeeTypeEntity(JdbcType.SMALLINT, "NUMBER", Short.class.getName(), "4", 0, new ShortHandler()),
            new BeeTypeEntity(JdbcType.INTEGER, "NUMBER", Integer.class.getName(), "11", 0, new IntegerHandler()),
            new BeeTypeEntity(JdbcType.BIGINT, "NUMBER", Long.class.getName(), "20", 1, new LongHandler()),
            new BeeTypeEntity(JdbcType.FLOAT, "FLOAT", Float.class.getName(), "1", 0, new FloatHandler()),
            new BeeTypeEntity(JdbcType.REAL, "REAL", Float.class.getName(), "0", 0, new FloatHandler()),
            new BeeTypeEntity(JdbcType.DOUBLE, "FLOAT", Double.class.getName(), "10,2", 1, new DoubleHandler()),
            new BeeTypeEntity(JdbcType.NUMERIC, "NUMBER", Double.class.getName(), "0", 0, new DoubleHandler()),
            new BeeTypeEntity(JdbcType.DECIMAL, "NUMBER", java.math.BigDecimal.class.getName(), "0", 0, new BigDecimalHandler()),
            new BeeTypeEntity(JdbcType.CHAR, "CHAR", String.class.getName(), "1", 0, new StringHandler()),
            new BeeTypeEntity(JdbcType.VARCHAR, "VARCHAR2", String.class.getName(), "255", 1, new StringHandler()),
            new BeeTypeEntity(JdbcType.LONGVARCHAR, "LONG", String.class.getName(), "255", 0, new StringHandler()),
			new BeeTypeEntity(JdbcType.DATE, "DATE", Date.class.getName(), "6", 0, new DateHandler()),
			new BeeTypeEntity(JdbcType.TIMESTAMP, "TIMESTAMP", Timestamp.class.getName(), "6", 0, new DateHandler()),
            new BeeTypeEntity(JdbcType.TIME, "TIME", java.sql.Time.class.getName(), "0", 0, new DateHandler()),
            new BeeTypeEntity(JdbcType.BINARY, "VARCHAR2", Byte.class.getName(), "1", 0, new ByteHandler()),
            new BeeTypeEntity(JdbcType.TIMESTAMP, "TIMESTAMP", LocalDateTime.class.getName(), "6", 0, new LocalDateTimeHandler()),
            new BeeTypeEntity(JdbcType.DATE, "DATE", LocalDate.class.getName(), "0", 0, new LocalDateHandler()),
            new BeeTypeEntity(JdbcType.TIME, "TIME", LocalTime.class.getName(), "1", 0, new LocalTimeHandler()),
            new BeeTypeEntity(JdbcType.VARBINARY, "RAW", Byte.class.getName(), "4", 0, new ByteHandler()),
            new BeeTypeEntity(JdbcType.LONGVARBINARY, "LONGVARBINARY", Byte.class.getName(), "4", 0, new ByteHandler()),
            new BeeTypeEntity(JdbcType.BLOB, "BLOB", java.sql.Blob.class.getName(), "0", 1, new BlobHandler()),
            new BeeTypeEntity(JdbcType.CLOB, "CLOB", java.sql.Clob.class.getName(), "0", 1, new ClobHandler()),
            new BeeTypeEntity(JdbcType.OTHER, "VARCHAR2", String.class.getName(), "255", 0, new StringHandler())
    ));

    private Map<String, BeeTypeEntity> javaMapping;

    public Set<BeeTypeEntity> getMapping() {
        return allMapping;
    }

    @Override
    public Map<JdbcType, BeeTypeEntity> getJdbcMap() {
        return allMapping.stream().collect(Collectors.toMap(BeeTypeEntity::getJdbcType, obj -> obj, (key1, key2) -> key1));
    }

    @Override
    public Map<String, BeeTypeEntity> getJavaMap() {
        return initJavaTypeMap(allMapping);
	}

	@Override
	public String getCreateTable(BaseEntity entiry) {
		return "CREATE TABLE %s ( " + buildFiledSql(entiry, BeeDataSourceType.ORACLE_WRAP)
				+ ")";
	}

	@Override
	public String getTableStruct(String tabName) {
		return "select * from " + tabName + " where ROWNUM < 1";
	}

	public String getFiledLenght(String clazz,String length) {
		clazz = ClassUtil.getSimpleName(clazz);
		if (clazz.equals(Integer.class.getName()) || clazz.equals(Clob.class.getName()) || clazz.equals(Blob.class.getName())
			|| clazz.equals(Timestamp.class.getName())) {
			return "";
		}
        if (clazz.equals(Date.class.getName()) && Integer.parseInt(length) > 6) {
            length = "6";
        }
		return " ("+length+") ";
	}

	@Override
	public String getTableStructDetail(ArcSharding arc) {
		  String sql = "select a.table_name,a.COLUMN_NAME,a.DATA_TYPE,b.comments COLUMN_COMMENT from user_tab_columns a,user_col_comments b where a.table_name=b.table_name and a.column_name=b.column_name";
          if (arc.table() != null) {
              sql = sql + " and a.table_name = '" + arc.table() + "'";
          }
          return sql;
	}
	
	@Override
	public String getAutoIncrement(boolean primary) {		
		if(primary){
			return " primary key ";
		}
		return "";
	}

	@Override
	public String getTabName( ArcSharding arc) {
		if(ObjectUtils.isEmpty(arc.userName()))
			return arc.table();
		return arc.userName()+"."+arc.table();
	}

	
	@Override
	public void initPramaryIncrement(BaseEntity entity) {
		String tableName = TableUtils.getTableName(entity);
		//查看主键字段是否存在 @id字段
		
		JdbcTemplate jdbcTemplate = BeeSpringBean.getBean(JdbcTemplate.class);
		//添加一个序列
		String seqSql = "CREATE SEQUENCE "+tableName+"_sequence"+"\r\n"+
						"increment by 1"+ "\r\n"+                 
						"start with 1"+"\r\n"+                    
						"nomaxvalue"+"\r\n"+                     
						"nocycle"+"\r\n"+                     
						"nocache";
		try{
			jdbcTemplate.execute(seqSql);
		}catch(Exception e){
			BizLogger.error(e);
		}
		String pramary = SqlProvider.getPramaryKey(entity);
		if(ObjectUtils.isEmpty(pramary)) {
			return;
		}
		//添加一个触发器
		String tiggertSql = "create trigger "+tableName+"_trig before "+
							"insert on "+tableName+" for each row when (new."+pramary+" is null) "+
							"begin "+
								"select "+tableName+"_sequence.nextval into:new."+pramary+" from dual; "+
 							"end;";
		try{
			jdbcTemplate.execute(tiggertSql);
		}catch(Exception e){
			BizLogger.error(e);
		}
	}

	@Override
	public String getAlertAdd(boolean isUpdate) {
		if(isUpdate){
			return " ";
		}else{
			return " ,";
		}
	}
	@Override
	public String getComment(String comment) {

		return "";
	}
	@Override
	public String getAlertDrop(List<String> fieldNames) {
		return " drop (" + StrUtils.join(fieldNames, ",") +
				")";
	}

	@Override
	public String trancationField(Object o,String condition) {
		if(o instanceof Date date){
			//判断是否是10位
			if(ObjectUtils.isEmpty(o)){
				return null;
			}
			if(date.getHours()==0 && date.getMinutes()==0 && date.getSeconds()==0){
				SimpleDateFormat sdf = new SimpleDateFormat(TimeUtils.DATE_FORMAT_DATEONLY);
				return " to_date('"
				+ sdf.format(TimeUtils.parse(o.toString()))
				+ "','yyyy-mm-dd')";
			}else{
				SimpleDateFormat sdf = new SimpleDateFormat(TimeUtils.DATE_FORMAT_DATETIME);
				return " to_date('"
					+ sdf.format(TimeUtils.parse(o.toString()))
					+ "','yyyy-mm-dd hh24:mi:ss')";
			}
		}
		return null;
	}
	
	@SuppressWarnings("rawtypes")
	@Override
	public String insertBaseList(Map<String, Object> para) {
		List list = (List) para.get("list");
		StrUtils.notNull(list, "list is null");
		String tableName = TableUtils.getTableName((BaseEntity) list.get(0));
		return "<script>" +
				"insert all " +
				"<foreach collection=\"list\" item=\"item\" index=\"index\" separator=\"\">" +
				" into " + tableName +
				"(" + InsertSqlProvider.getInsertFiled((BaseEntity) list.get(0), true) + ")" +
				" VALUES " +
				"(" +
				InsertSqlProvider.getInsertFiledValue((BaseEntity) list.get(0), true) +
				")" +
				"</foreach>" +
				" SELECT * FROM dual " +
				"</script>";
    }
}
